Skip to content

Calculate power for int64 exponent precisely - #289

Merged
MichaelChirico merged 17 commits into
mainfrom
power64
Aug 17, 2026
Merged

Calculate power for int64 exponent precisely#289
MichaelChirico merged 17 commits into
mainfrom
power64

Conversation

@hcirellu

Copy link
Copy Markdown
Collaborator

I added a precise calculation for POW64 with an overflow detection.

The example from #288 now returns the correct values.

x = as.integer64(c("94906267", "2147483650"))
> x^2L
integer64
[1] 9007199515875289    4611686027017322500

The results for double exponent are unchanged, i.e.:

x = as.integer64(c("94906267", "2147483650"))
> x^2
integer64
[1] 9007199515875288    4611686027017322496

In addition, the new implementation is faster, too.

x = as.integer64(sample(-100:100,rep=T,1000000))
y32 = 0:9
yd = as.double(y32)
microbenchmark::microbenchmark(x^y32, x^yd)
# Unit: milliseconds
#   expr       min        lq     mean    median        uq      max neval
#  x^y32  6.262101  6.566502 13.84232  6.816252  7.256201 178.3225   100
#   x^yd 27.294501 27.965501 30.46499 28.709051 31.592151  66.1929   100

Closes #288

@hcirellu
hcirellu marked this pull request as ready for review March 11, 2026 11:49
@MichaelChirico MichaelChirico added this to the 4.8.0 milestone Mar 11, 2026
@MichaelChirico

Copy link
Copy Markdown
Collaborator

Related: #362, which basically proposes using the canonical __builtin_mul_overflow and winds up much cleaner (IMHO).

Comment thread src/integer64.h Outdated
Comment thread src/integer64.h Outdated
@MichaelChirico

MichaelChirico commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

I don't find quite as big an improvement as in the original finding, but we're about par with it:

# on main
Unit: milliseconds
  expr      min       lq     mean   median       uq       max neval
 x^y32 38.52712 38.98665 45.70925 39.26639 41.23708 114.25858   100
  x^yd 37.42355 37.67720 38.82385 37.97289 39.23138  68.71753   100

# commit 8ab076d
Unit: milliseconds
  expr      min       lq     mean   median       uq      max neval
 x^y32 17.40987 17.66348 22.28280 17.90434 20.43980 83.21028   100
  x^yd 37.24897 37.64709 38.33571 37.85837 38.61876 41.50529   100

# commit c3354f7 (with GOODIPROD macro patched in again)
Unit: milliseconds
  expr      min       lq     mean   median       uq      max neval
 x^y32 15.77875 15.98049 24.42159 17.42407 18.53971 85.62482   100
  x^yd 37.41362 37.65100 38.28342 37.79927 38.76750 42.17372   100

@MichaelChirico

Copy link
Copy Markdown
Collaborator

OK, I'm happy enough with this now. We can iterate more if needed. The seed of your idea (base*=base approach to get log(exp) performance) is still here, thanks!

@MichaelChirico
MichaelChirico merged commit 97bbd63 into main Aug 17, 2026
13 checks passed
@MichaelChirico
MichaelChirico deleted the power64 branch August 17, 2026 06:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Power of integer64 is not precise

2 participants